package com.vpen.springsecuritytest.securitylogin;

import com.vpen.springsecuritytest.pojo.User;
import com.vpen.springsecuritytest.service.UserService;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * -@Version 1.0
 * -@Author:Vpen
 * -@Date:2021/3/13 19:52
 * -@Content:
 */

@Component(value = "myDetailsService")
public class UserServiceImpl implements UserDetailsService {
    @Resource(name = "userSI")
    UserService userService;

    /**
    * -@author Vpen
    * -@name getRoleAndResource
    * -@date 2021/3/14 23:53
    * -@param [user]
    * -@return java.lang.String[]
    * -@作用:返回用户的拼接角色和资源权限
    */
    private String[] getRoleAndResource(User user){

        List<String> resource = userService.selectResourceByUser(user);
        List<String> role = userService.selectRoleByUser(user);

        // 把角色和资源访问放入一个数组中
        String[] authorities = new String[role.size() + resource.size()];
        for (int i = 0; i < role.size(); i++) {
            // 在SpringSecurity中，
            // 对角色的命名有严格的规则，要求角色的名称前缀必须是"ROLE_"，
            // 不要在数据库中保存这个前缀的开头
            authorities[i]="ROLE_"+role.get(i);
        }
        for (int i = 0; i < resource.size(); i++) {
            authorities[i+ role.size()]= resource.get(i);
        }
        return authorities;
    }


    @Override
    public UserDetails loadUserByUsername(String name)
            throws UsernameNotFoundException {

        User user = userService.login(name);
        if (user==null) {
            // 查询失败，用户名不存在，抛出异常
            throw new UsernameNotFoundException("用户名不存在！");
        }
        /* *
         * 作者:Vpen
         * 描述:
         * 查询成功，用户存储，需要匹配用户密码是否正确
         * 匹配密码，是由SpringSecurity内部逻辑自动完成，只需要把查询的用户正确密码返回即可
         * 返回结果师UserDetails的实现类，可以自定义，可以使用框架提供的实现类User
         * 三个构造函数：用户名、用户密码、权限集合(就是权限角色放入一个集合)
         * */
        return new org.springframework.security.core.userdetails.User(
                user.getName(),
                user.getPwd(),
                AuthorityUtils.createAuthorityList(getRoleAndResource(user))// 拼接好的角色和资源权限
                );
    }
}
